function mdl = slgaussest(type, X, w, varargin)
%SLGAUSSEST Estimates Gaussian model(s) from data
%
% [ Syntax ]
%   - mdl = slgaussest(type, X, w, ...)
%
% [ Arguments ]
%   - type:         The type of Gaussian model(s)
%   - X:            The sample matrix
%   - w:            The matrix of weights
%   - mdl:          The estimated model
%
% [ Description ]
%   - mdl = slgaussest(type, X, w, ...) estimates the Gaussian model from
%     data.
%
%     You should specify the type of model(s) that you intend to estimate,
%     there are three types:
%       \{:
%           - 'full':       the Gaussian model with full-form covariance
%           - 'diag':       the Gaussian model with diagonal form of
%                           covariance
%           - 'iso':        the Gaussian model with isotropic form of
%                           covariance
%       \:}
%
%     Suppose there are n samples in d-dimensional space, then X should be
%     an d x n matrix with each column giving a sample. 
%
%     w can be either of the following forms:
%       - w is empty array, then it estimates a model based on samples
%         which are not weighted
%       - w is a 1 x n row vector, then it estimates a model based on
%         the weighted samples
%       - w is a K x n matrix, then it estimates models, and each 
%         model corresponds to a row of weights.
%
%     You may further specify the following options for estimation:
%       \{:
%           - 'sharecov':       whether to share the covariance among
%                               models (default = false)
%           - 'cachelevel':     the level of pre-computation caching
%                               in estimated model.
%                               By default, it is set to the highest
%                               level for the specified type.
%       \:}
%
% [ History ]
%   - Created by Dahua Lin, on Dec 26, 2007
%

%% parse and verify input arguments

assert(ischar(type), 'sltoolbox:slgaussest:invalidarg', ...
    'The model type should be a string.');

assert(isnumeric(X) && ndims(X) == 2, ...
    'sltoolbox:slgaussest:invalidarg', ...
    'The sample matrix X should be a 2D numeric matrix.');

n = size(X, 2);

if nargin < 3
    w = [];
else
    if ~isempty(w)
        assert(isnumeric(w) && ndims(w) == 2 && size(w, 2) == n, ...
            'sltoolbox:slgaussest:invalidarg', ...
            'The weight matrix should be a 2D numeric matrix with n columns.');
    end
end

opts = struct('sharecov',true, 'cachelevel', []);
if nargin >= 4
    opts = slsetopts(opts, varargin{:});
    
    if ~isempty(opts.cachelevel)
        assert(isnumeric(opts.cachelevel) && isscalar(opts.cachelevel) && opts.cachelevel >= 0, ...
            'sltoolbox:slgaussest:invalidopt', ...
            'cachelevel should be a nonnegative numeric scalar.');
    end
    
end

if opts.sharecov
    copts = 'sharecov';
else
    copts = '';
end



%% main

switch type
    case 'full'
        cachelevel = get_cachelevel(opts.cachelevel, 3);
        mdl = estimate(slcfullgauss, X, w, copts, cachelevel);
        
    case 'diag'
        cachelevel = get_cachelevel(opts.cachelevel, 2);
        mdl = estimate(slcdiaggauss, X, w, copts, cachelevel);
        
    case 'iso'
        mdl = estimate(slcisogauss, X, w, copts);
        
    otherwise
        error('sltoolbox:slgaussest:invalidarg', ...
            'Invalid model type: %s', type);
end


%% supporting function

function c = get_cachelevel(c_in, v)

if isempty(c_in)
    c = v;
else
    c = c_in;
end








